library(plotly)
library(dplyr)
#plotly code:
plotlyOutput('pcp')

output$pcp <- renderPlotly({
        
 
      pcdat<- dat[1:54,c(2,18,27, 29)] %>% subset(!is.na(dat[1:54,29]))
      party <-dat[1:54,29] %>% subset(!is.na(dat[,29])) %>%  unique() 
      col_names <- sapply(pcdat, is.factor)
      pcdat[,col_names] <- sapply(pcdat[,col_names] , unclass)
      
      library(plotly) 
      pcdat %>% plot_ly() %>% add_trace(type = 'parcoords', line = list(color = ~Governor.Political.Affiliation, colorscale = list(c(0,'blue'),c(1,'red'))),
                                        dimensions = list(
                                          list(range = c(1,50),
                                               tickvals = c(1:50),
                                               label = 'state',
                                               ticktext = c(paste(dat$state)),
                                               values = ~state ),
                                          
                                          list(range = c(~min(total),~max(total)),
                                               label = 'total tests',
                                               tickvals = c(~min(total),~max(total)),
                                               values= ~total),
                                          
                                          list(range=c(1,2),
                                               tickvals = c(1, 2),
                                               label = 'party',
                                               ticktext = c(paste(party)),
                                               values = ~Governor.Political.Affiliation ),
                                          
                                          list(range = c(1,7),
                                               tickvals = c(1,7),
                                               label = 'school closure date',
                                               ticktext = c(paste(dat$StateClosureStartDate)),
                                               values = ~StateClosureStartDate
                                          )
                                        )
                                        
                                        
      )
      
    })
  fig <- pcdat %>% plot_ly(width = 1000, height = 600) 
      #fig %>% 
      pcdat<- dat[1:54,c(2,18,27, 29)] %>% subset(!is.na(dat[1:54,29]))
      party <-dat[1:54,29] %>% subset(!is.na(dat[,29])) %>%  unique() 
      col_names <- sapply(pcdat, is.factor)
      pcdat[,col_names] <- sapply(pcdat[,col_names] , unclass)
      
      library(plotly) 
      #options(viewer=NULL)
      pcdat %>% plot_ly() %>% add_trace(type = 'parcoords', line = list(color = ~Governor.Political.Affiliation, colorscale = list(c(0,'blue'),c(1,'red'))),
                                        dimensions = list(
                                          list(range = c(1,50),
                                               tickvals = c(1:50),
                                               label = 'state',
                                               ticktext = c(paste(dat$state)),
                                               values = ~state ),
                                          
                                          list(range = c(~min(total),~max(total)),
                                               label = 'total tests',
                                               tickvals = c(~min(total),~max(total)),
                                               values= ~total),
                                          
                                          list(range=c(1,2),
                                               tickvals = c(1, 2),
                                               label = 'party',
                                               ticktext = c(paste(party)),
                                               values = ~Governor.Political.Affiliation ),
                                          
                                          list(range = c(1,7),
                                               tickvals = c(1,7),
                                               label = 'school closure date',
                                               ticktext = c(paste(dat$StateClosureStartDate)),
                                               values = ~StateClosureStartDate
                                          )
                                        )
                                        
                                        
      )

NA
fig <- pcdat %>% plot_ly(width = 1000, height = 600) 
#fig %>% 
pcdat<- dat[1:54,c(2,18,27, 29)] %>% subset(!is.na(dat[1:54,29]))
party <-dat[1:54,29] %>% subset(!is.na(dat[,29])) %>%  unique() 
col_names <- sapply(pcdat, is.factor)
pcdat[,col_names] <- sapply(pcdat[,col_names] , unclass)

library(plotly) 
#options(viewer=NULL)
pcdat %>% plot_ly() %>% add_trace(type = 'parcoords', line = list(color = ~Governor.Political.Affiliation, colorscale = list(c(0,'blue'),c(1,'red'))),
dimensions = list(
  list(range = c(1,50),
       tickvals = c(1:50),
       label = 'state',
       ticktext = c(paste(dat$state)),
       values = ~state ),
  
  list(range = c(~min(total),~max(total)),
       label = 'total tests',
       tickvals = c(~min(total),~max(total)),
       values= ~total),

list(range=c(1,2),
     tickvals = c(1, 2),
     label = 'party',
     ticktext = c(paste(party)),
     values = ~Governor.Political.Affiliation ),

list(range = c(1,7),
     tickvals = c(1,7),
     label = 'school closure date',
     ticktext = c(paste(dat$StateClosureStartDate)),
     values = ~StateClosureStartDate
                  )
     )
                  
                
)

An example parallel coordinate plot to use as a template. This code is from Plotly documentation: https://plotly.com/r/parallel-coordinates-plot/

df <- read.csv("https://raw.githubusercontent.com/bcdunbar/datasets/master/parcoords_data.csv")

fig <- df %>%
  plot_ly(width = 1000, height = 600) 
fig <- fig %>% add_trace(type = 'parcoords',
          # line = list(color = ~colorVal,
          #             colorscale = 'Jet',
          #             showscale = TRUE,
          #             reversescale = TRUE,
          #             cmin = -4000,
          #             cmax = -100),
          dimensions = list(
            list(range = c(~min(blockHeight),~max(blockHeight)),
                 constraintrange = c(100000,150000),
                 label = 'Block Height', values = ~blockHeight),
            list(range = c(~min(blockWidth),~max(blockWidth)),
                 label = 'Block Width', values = ~blockWidth),
            list(tickvals = c(0,0.5,1,2,3),
                 ticktext = c('A','AB','B','Y','Z'),
                 label = 'Cyclinder Material', values = ~cycMaterial),
            list(range = c(-1,4),
                 tickvals = c(0,1,2,3),
                 label = 'Block Material', values = ~blockMaterial),
            list(range = c(~min(totalWeight),~max(totalWeight)),
                 visible = TRUE,
                 label = 'Total Weight', values = ~totalWeight),
            list(range = c(~min(assemblyPW),~max(assemblyPW)),
                 label = 'Assembly Penalty Weight', values = ~assemblyPW),
            list(range = c(~min(HstW),~max(HstW)),
                 label = 'Height st Width', values = ~HstW),
            list(range = c(~min(minHW),~max(minHW)),
                 label = 'Min Height Width', values = ~minHW),
            list(range = c(~min(minWD),~max(minWD)),
                 label = 'Min Width Diameter', values = ~minWD),
            list(range = c(~min(rfBlock),~max(rfBlock)),
                 label = 'RF Block', values = ~rfBlock)
            )
          )


fig
head(df)

On to our code. Merge the two datasets and join them on the state abbreviation.

Define the regions based on CDC standards:

#define regions based on CDC standards (https://www.cdc.gov/coronavirus/2019-ncov/covid-data/covidview/04102020/labs-regions.html)

R1 <- c('CT', 'ME', 'MA', 'NH', 'RI', 'VT')
R2 <- c('NJ', 'NY', 'PR')
R3 <- c('DE', 'DC', 'MD', 'PA', 'VA', 'WV')
R4 <- c('AL', 'FL', 'GA', 'KY', 'MS', 'NC', 'SC', 'TN')
R5 <- c('IL', 'IN', 'MI','MN','OH','WI')
R6 <- c('AR','LA','NM','OK','TX')
R7 <- c('IA', 'KS', 'MO', 'NE')
R8 <- c('CO', 'MT', 'ND','SD','UT','WY')
R9 <- c('AZ', 'CA', 'GU', 'HI','NV')
R10 <- c('AK','ID','OR','WA')

#put as character so that all states/territories have a value and all values of same type of vector
dat <- dat %>% mutate(region = (
  case_when(state %in% R1 ~ '1',
            state %in% R2 ~ '2',
            state %in% R3 ~ '3',
            state %in% R4 ~ '4',
            state %in% R5 ~ '5',
            state %in% R6 ~ '6',
            state %in% R7 ~ '7',
            state %in% R8 ~ '8',
            state %in% R9 ~ '9',
            state %in% R10 ~ '10', 
            TRUE ~ 'Other')
))
#Reference Documentation : https://plotly.com/r/reference/#parcoords

#DO NOT RUN YET. have not updated completely
fig <- dat %>%
  plot_ly(width = 1000, height = 600) 
fig <- fig %>% add_trace(type = 'parcoords', name = ~state,
          dimensions = list(
            list(tickvals = c(0:50),
                 ticktext = c(dat$state),
                 label = 'State', values = ~state),
            list(
              range=c(~min(totalTestResults), ~max(totalTestResults)),
              label = 'Total Tests',
              values = ~totalTestResults)
            
            # list(range = c(~min(blockHeight),~max(blockHeight)),
            #      constraintrange = c(100000,150000),
            #      label = 'Block Height', values = ~blockHeight),
            # list(range = c(~min(blockWidth),~max(blockWidth)),
            #      label = 'Block Width', values = ~blockWidth),
            # list(tickvals = c(0,0.5,1,2,3),
            #      ticktext = c('A','AB','B','Y','Z'),
            #      label = 'Cyclinder Material', values = ~cycMaterial),
            # list(range = c(-1,4),
            #      tickvals = c(0,1,2,3),
            #      label = 'Block Material', values = ~blockMaterial),
            # list(range = c(~min(totalWeight),~max(totalWeight)),
            #      visible = TRUE,
            #      label = 'Total Weight', values = ~totalWeight),
            # list(range = c(~min(assemblyPW),~max(assemblyPW)),
            #      label = 'Assembly Penalty Weight', values = ~assemblyPW),
            # list(range = c(~min(HstW),~max(HstW)),
            #      label = 'Height st Width', values = ~HstW),
            # list(range = c(~min(minHW),~max(minHW)),
            #      label = 'Min Height Width', values = ~minHW),
            # list(range = c(~min(minWD),~max(minWD)),
            #      label = 'Min Width Diameter', values = ~minWD),
            # list(range = c(~min(rfBlock),~max(rfBlock)),
            #      label = 'RF Block', values = ~rfBlock)
            )
          )


fig

GGally more difficult to do categorical data, but way to separate out groups, scale the data (univariately, substract mean & divide by sd)

library(GGally)
dat %>% arrange(desc(region))%>%
   ggparcoord(
    columns = c(18,29), groupColumn = 32
    ) +
    scale_color_manual(values=c( "#69b3a2", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8", "#E8E8E8") ) 

 #can factor regions
#dat %>% colnames()

THIS ONE!! cdparcoord

LS0tCnRpdGxlOiAiNzA2IFBhcmFsbGVsIENvb3JkaW5hdGVzIgphdXRob3I6ICdEYW55IFRob3JwZSBIdWVydGEnCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShkcGx5cikKYGBgCgoKYGBge3IsIGV2YWwgPSBGfQojcGxvdGx5IGNvZGU6CnBsb3RseU91dHB1dCgncGNwJykKCm91dHB1dCRwY3AgPC0gcmVuZGVyUGxvdGx5KHsKICAgICAgICAKIAogICAgICBwY2RhdDwtIGRhdFsxOjU0LGMoMiwxOCwyNywgMjkpXSAlPiUgc3Vic2V0KCFpcy5uYShkYXRbMTo1NCwyOV0pKQogICAgICBwYXJ0eSA8LWRhdFsxOjU0LDI5XSAlPiUgc3Vic2V0KCFpcy5uYShkYXRbLDI5XSkpICU+JSAgdW5pcXVlKCkgCiAgICAgIGNvbF9uYW1lcyA8LSBzYXBwbHkocGNkYXQsIGlzLmZhY3RvcikKICAgICAgcGNkYXRbLGNvbF9uYW1lc10gPC0gc2FwcGx5KHBjZGF0Wyxjb2xfbmFtZXNdICwgdW5jbGFzcykKICAgICAgCiAgICAgIGxpYnJhcnkocGxvdGx5KSAKICAgICAgcGNkYXQgJT4lIHBsb3RfbHkoKSAlPiUgYWRkX3RyYWNlKHR5cGUgPSAncGFyY29vcmRzJywgbGluZSA9IGxpc3QoY29sb3IgPSB+R292ZXJub3IuUG9saXRpY2FsLkFmZmlsaWF0aW9uLCBjb2xvcnNjYWxlID0gbGlzdChjKDAsJ2JsdWUnKSxjKDEsJ3JlZCcpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1lbnNpb25zID0gbGlzdCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChyYW5nZSA9IGMoMSw1MCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3ZhbHMgPSBjKDE6NTApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ3N0YXRlJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrdGV4dCA9IGMocGFzdGUoZGF0JHN0YXRlKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gfnN0YXRlICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKHRvdGFsKSx+bWF4KHRvdGFsKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAndG90YWwgdGVzdHMnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t2YWxzID0gYyh+bWluKHRvdGFsKSx+bWF4KHRvdGFsKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPSB+dG90YWwpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChyYW5nZT1jKDEsMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3ZhbHMgPSBjKDEsIDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ3BhcnR5JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrdGV4dCA9IGMocGFzdGUocGFydHkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSB+R292ZXJub3IuUG9saXRpY2FsLkFmZmlsaWF0aW9uICksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYygxLDcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t2YWxzID0gYygxLDcpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gJ3NjaG9vbCBjbG9zdXJlIGRhdGUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t0ZXh0ID0gYyhwYXN0ZShkYXQkU3RhdGVDbG9zdXJlU3RhcnREYXRlKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gflN0YXRlQ2xvc3VyZVN0YXJ0RGF0ZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICApCiAgICAgIAogICAgfSkKYGBgCgpgYGB7cn0KICBmaWcgPC0gcGNkYXQgJT4lIHBsb3RfbHkod2lkdGggPSAxMDAwLCBoZWlnaHQgPSA2MDApIAogICAgICAjZmlnICU+JSAKICAgICAgcGNkYXQ8LSBkYXRbMTo1NCxjKDIsMTgsMjcsIDI5KV0gJT4lIHN1YnNldCghaXMubmEoZGF0WzE6NTQsMjldKSkKICAgICAgcGFydHkgPC1kYXRbMTo1NCwyOV0gJT4lIHN1YnNldCghaXMubmEoZGF0WywyOV0pKSAlPiUgIHVuaXF1ZSgpIAogICAgICBjb2xfbmFtZXMgPC0gc2FwcGx5KHBjZGF0LCBpcy5mYWN0b3IpCiAgICAgIHBjZGF0Wyxjb2xfbmFtZXNdIDwtIHNhcHBseShwY2RhdFssY29sX25hbWVzXSAsIHVuY2xhc3MpCiAgICAgIAogICAgICBsaWJyYXJ5KHBsb3RseSkgCiAgICAgICNvcHRpb25zKHZpZXdlcj1OVUxMKQogICAgICBwY2RhdCAlPiUgcGxvdF9seSgpICU+JSBhZGRfdHJhY2UodHlwZSA9ICdwYXJjb29yZHMnLCBsaW5lID0gbGlzdChjb2xvciA9IH5Hb3Zlcm5vci5Qb2xpdGljYWwuQWZmaWxpYXRpb24sIGNvbG9yc2NhbGUgPSBsaXN0KGMoMCwnYmx1ZScpLGMoMSwncmVkJykpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbWVuc2lvbnMgPSBsaXN0KAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KHJhbmdlID0gYygxLDUwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrdmFscyA9IGMoMTo1MCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAnc3RhdGUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t0ZXh0ID0gYyhwYXN0ZShkYXQkc3RhdGUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSB+c3RhdGUgKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4odG90YWwpLH5tYXgodG90YWwpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICd0b3RhbCB0ZXN0cycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3ZhbHMgPSBjKH5taW4odG90YWwpLH5tYXgodG90YWwpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9IH50b3RhbCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KHJhbmdlPWMoMSwyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aWNrdmFscyA9IGMoMSwgMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAncGFydHknLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t0ZXh0ID0gYyhwYXN0ZShwYXJ0eSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IH5Hb3Zlcm5vci5Qb2xpdGljYWwuQWZmaWxpYXRpb24gKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKDEsNyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3ZhbHMgPSBjKDEsNyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAnc2Nob29sIGNsb3N1cmUgZGF0ZScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja3RleHQgPSBjKHBhc3RlKGRhdCRTdGF0ZUNsb3N1cmVTdGFydERhdGUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSB+U3RhdGVDbG9zdXJlU3RhcnREYXRlCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICkKICAgICAgCmBgYAoKCmBgYHtyfQpmaWcgPC0gcGNkYXQgJT4lIHBsb3RfbHkod2lkdGggPSAxMDAwLCBoZWlnaHQgPSA2MDApIAojZmlnICU+JSAKcGNkYXQ8LSBkYXRbMTo1NCxjKDIsMTgsMjcsIDI5KV0gJT4lIHN1YnNldCghaXMubmEoZGF0WzE6NTQsMjldKSkKcGFydHkgPC1kYXRbMTo1NCwyOV0gJT4lIHN1YnNldCghaXMubmEoZGF0WywyOV0pKSAlPiUgIHVuaXF1ZSgpIApjb2xfbmFtZXMgPC0gc2FwcGx5KHBjZGF0LCBpcy5mYWN0b3IpCnBjZGF0Wyxjb2xfbmFtZXNdIDwtIHNhcHBseShwY2RhdFssY29sX25hbWVzXSAsIHVuY2xhc3MpCgpsaWJyYXJ5KHBsb3RseSkgCiNvcHRpb25zKHZpZXdlcj1OVUxMKQpwY2RhdCAlPiUgcGxvdF9seSgpICU+JSBhZGRfdHJhY2UodHlwZSA9ICdwYXJjb29yZHMnLCBsaW5lID0gbGlzdChjb2xvciA9IH5Hb3Zlcm5vci5Qb2xpdGljYWwuQWZmaWxpYXRpb24sIGNvbG9yc2NhbGUgPSBsaXN0KGMoMCwnYmx1ZScpLGMoMSwncmVkJykpKSwKZGltZW5zaW9ucyA9IGxpc3QoCiAgbGlzdChyYW5nZSA9IGMoMSw1MCksCiAgICAgICB0aWNrdmFscyA9IGMoMTo1MCksCiAgICAgICBsYWJlbCA9ICdzdGF0ZScsCiAgICAgICB0aWNrdGV4dCA9IGMocGFzdGUoZGF0JHN0YXRlKSksCiAgICAgICB2YWx1ZXMgPSB+c3RhdGUgKSwKICAKICBsaXN0KHJhbmdlID0gYyh+bWluKHRvdGFsKSx+bWF4KHRvdGFsKSksCiAgICAgICBsYWJlbCA9ICd0b3RhbCB0ZXN0cycsCiAgICAgICB0aWNrdmFscyA9IGMofm1pbih0b3RhbCksfm1heCh0b3RhbCkpLAogICAgICAgdmFsdWVzPSB+dG90YWwpLAoKbGlzdChyYW5nZT1jKDEsMiksCiAgICAgdGlja3ZhbHMgPSBjKDEsIDIpLAogICAgIGxhYmVsID0gJ3BhcnR5JywKICAgICB0aWNrdGV4dCA9IGMocGFzdGUocGFydHkpKSwKICAgICB2YWx1ZXMgPSB+R292ZXJub3IuUG9saXRpY2FsLkFmZmlsaWF0aW9uICksCgpsaXN0KHJhbmdlID0gYygxLDcpLAogICAgIHRpY2t2YWxzID0gYygxLDcpLAogICAgIGxhYmVsID0gJ3NjaG9vbCBjbG9zdXJlIGRhdGUnLAogICAgIHRpY2t0ZXh0ID0gYyhwYXN0ZShkYXQkU3RhdGVDbG9zdXJlU3RhcnREYXRlKSksCiAgICAgdmFsdWVzID0gflN0YXRlQ2xvc3VyZVN0YXJ0RGF0ZQogICAgICAgICAgICAgICAgICApCiAgICAgKQogICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIAopCgpgYGAKCkFuIGV4YW1wbGUgcGFyYWxsZWwgY29vcmRpbmF0ZSBwbG90IHRvIHVzZSBhcyBhIHRlbXBsYXRlLiBUaGlzIGNvZGUgaXMgZnJvbSBQbG90bHkgZG9jdW1lbnRhdGlvbjogaHR0cHM6Ly9wbG90bHkuY29tL3IvcGFyYWxsZWwtY29vcmRpbmF0ZXMtcGxvdC8KYGBge3IgVGVtcGxhdGV9CmRmIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vYmNkdW5iYXIvZGF0YXNldHMvbWFzdGVyL3BhcmNvb3Jkc19kYXRhLmNzdiIpCgpmaWcgPC0gZGYgJT4lCiAgcGxvdF9seSh3aWR0aCA9IDEwMDAsIGhlaWdodCA9IDYwMCkgCmZpZyA8LSBmaWcgJT4lIGFkZF90cmFjZSh0eXBlID0gJ3BhcmNvb3JkcycsCiAgICAgICAgICAjIGxpbmUgPSBsaXN0KGNvbG9yID0gfmNvbG9yVmFsLAogICAgICAgICAgIyAgICAgICAgICAgICBjb2xvcnNjYWxlID0gJ0pldCcsCiAgICAgICAgICAjICAgICAgICAgICAgIHNob3dzY2FsZSA9IFRSVUUsCiAgICAgICAgICAjICAgICAgICAgICAgIHJldmVyc2VzY2FsZSA9IFRSVUUsCiAgICAgICAgICAjICAgICAgICAgICAgIGNtaW4gPSAtNDAwMCwKICAgICAgICAgICMgICAgICAgICAgICAgY21heCA9IC0xMDApLAogICAgICAgICAgZGltZW5zaW9ucyA9IGxpc3QoCiAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4oYmxvY2tIZWlnaHQpLH5tYXgoYmxvY2tIZWlnaHQpKSwKICAgICAgICAgICAgICAgICBjb25zdHJhaW50cmFuZ2UgPSBjKDEwMDAwMCwxNTAwMDApLAogICAgICAgICAgICAgICAgIGxhYmVsID0gJ0Jsb2NrIEhlaWdodCcsIHZhbHVlcyA9IH5ibG9ja0hlaWdodCksCiAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4oYmxvY2tXaWR0aCksfm1heChibG9ja1dpZHRoKSksCiAgICAgICAgICAgICAgICAgbGFiZWwgPSAnQmxvY2sgV2lkdGgnLCB2YWx1ZXMgPSB+YmxvY2tXaWR0aCksCiAgICAgICAgICAgIGxpc3QodGlja3ZhbHMgPSBjKDAsMC41LDEsMiwzKSwKICAgICAgICAgICAgICAgICB0aWNrdGV4dCA9IGMoJ0EnLCdBQicsJ0InLCdZJywnWicpLAogICAgICAgICAgICAgICAgIGxhYmVsID0gJ0N5Y2xpbmRlciBNYXRlcmlhbCcsIHZhbHVlcyA9IH5jeWNNYXRlcmlhbCksCiAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKC0xLDQpLAogICAgICAgICAgICAgICAgIHRpY2t2YWxzID0gYygwLDEsMiwzKSwKICAgICAgICAgICAgICAgICBsYWJlbCA9ICdCbG9jayBNYXRlcmlhbCcsIHZhbHVlcyA9IH5ibG9ja01hdGVyaWFsKSwKICAgICAgICAgICAgbGlzdChyYW5nZSA9IGMofm1pbih0b3RhbFdlaWdodCksfm1heCh0b3RhbFdlaWdodCkpLAogICAgICAgICAgICAgICAgIHZpc2libGUgPSBUUlVFLAogICAgICAgICAgICAgICAgIGxhYmVsID0gJ1RvdGFsIFdlaWdodCcsIHZhbHVlcyA9IH50b3RhbFdlaWdodCksCiAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4oYXNzZW1ibHlQVyksfm1heChhc3NlbWJseVBXKSksCiAgICAgICAgICAgICAgICAgbGFiZWwgPSAnQXNzZW1ibHkgUGVuYWx0eSBXZWlnaHQnLCB2YWx1ZXMgPSB+YXNzZW1ibHlQVyksCiAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4oSHN0Vyksfm1heChIc3RXKSksCiAgICAgICAgICAgICAgICAgbGFiZWwgPSAnSGVpZ2h0IHN0IFdpZHRoJywgdmFsdWVzID0gfkhzdFcpLAogICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKG1pbkhXKSx+bWF4KG1pbkhXKSksCiAgICAgICAgICAgICAgICAgbGFiZWwgPSAnTWluIEhlaWdodCBXaWR0aCcsIHZhbHVlcyA9IH5taW5IVyksCiAgICAgICAgICAgIGxpc3QocmFuZ2UgPSBjKH5taW4obWluV0QpLH5tYXgobWluV0QpKSwKICAgICAgICAgICAgICAgICBsYWJlbCA9ICdNaW4gV2lkdGggRGlhbWV0ZXInLCB2YWx1ZXMgPSB+bWluV0QpLAogICAgICAgICAgICBsaXN0KHJhbmdlID0gYyh+bWluKHJmQmxvY2spLH5tYXgocmZCbG9jaykpLAogICAgICAgICAgICAgICAgIGxhYmVsID0gJ1JGIEJsb2NrJywgdmFsdWVzID0gfnJmQmxvY2spCiAgICAgICAgICAgICkKICAgICAgICAgICkKCgpmaWcKYGBgCgpgYGB7cn0KaGVhZChkZikKYGBgCgpPbiB0byBvdXIgY29kZS4gTWVyZ2UgdGhlIHR3byBkYXRhc2V0cyBhbmQgam9pbiB0aGVtIG9uIHRoZSBzdGF0ZSBhYmJyZXZpYXRpb24uCmBgYHtyIFJlYWQgRGF0YSwgaW5jbHVkZT1GQUxTRX0KZGF0IDwtIHJlYWQuY3N2KCIuLi9jb3ZpZF90cmFja2luZ19oaXN0b3J5LmNzdiIpCmRhdCRkYXRlIDwtIGFzLmZhY3RvcihkYXQkZGF0ZSkKCmRhdCA8LSBkYXQgJT4lIGZ1bGxfam9pbiguLCByZWFkLmNzdigiLi4vY29yb25hdmlydXMtc2Nob29sLWNsb3N1cmVzLWRhdGEtNC03LTIwMjAuY3N2IiksIGJ5ID0gYygnc3RhdGUnID0gJ1N0YXRlQWJicmV2aWF0aW9uJykpCmRhdCRTdGF0ZUNsb3N1cmVTdGFydERhdGUgPC0gYXMuRGF0ZShkYXQkU3RhdGVDbG9zdXJlU3RhcnREYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKQoKYGBgCgpEZWZpbmUgdGhlIHJlZ2lvbnMgYmFzZWQgb24gQ0RDIHN0YW5kYXJkczoKYGBge3IgUmVnaW9uIERlZmludGlvbn0KI2RlZmluZSByZWdpb25zIGJhc2VkIG9uIENEQyBzdGFuZGFyZHMgKGh0dHBzOi8vd3d3LmNkYy5nb3YvY29yb25hdmlydXMvMjAxOS1uY292L2NvdmlkLWRhdGEvY292aWR2aWV3LzA0MTAyMDIwL2xhYnMtcmVnaW9ucy5odG1sKQoKUjEgPC0gYygnQ1QnLCAnTUUnLCAnTUEnLCAnTkgnLCAnUkknLCAnVlQnKQpSMiA8LSBjKCdOSicsICdOWScsICdQUicpClIzIDwtIGMoJ0RFJywgJ0RDJywgJ01EJywgJ1BBJywgJ1ZBJywgJ1dWJykKUjQgPC0gYygnQUwnLCAnRkwnLCAnR0EnLCAnS1knLCAnTVMnLCAnTkMnLCAnU0MnLCAnVE4nKQpSNSA8LSBjKCdJTCcsICdJTicsICdNSScsJ01OJywnT0gnLCdXSScpClI2IDwtIGMoJ0FSJywnTEEnLCdOTScsJ09LJywnVFgnKQpSNyA8LSBjKCdJQScsICdLUycsICdNTycsICdORScpClI4IDwtIGMoJ0NPJywgJ01UJywgJ05EJywnU0QnLCdVVCcsJ1dZJykKUjkgPC0gYygnQVonLCAnQ0EnLCAnR1UnLCAnSEknLCdOVicpClIxMCA8LSBjKCdBSycsJ0lEJywnT1InLCdXQScpCgojcHV0IGFzIGNoYXJhY3RlciBzbyB0aGF0IGFsbCBzdGF0ZXMvdGVycml0b3JpZXMgaGF2ZSBhIHZhbHVlIGFuZCBhbGwgdmFsdWVzIG9mIHNhbWUgdHlwZSBvZiB2ZWN0b3IKZGF0IDwtIGRhdCAlPiUgbXV0YXRlKHJlZ2lvbiA9ICgKICBjYXNlX3doZW4oc3RhdGUgJWluJSBSMSB+ICcxJywKICAgICAgICAgICAgc3RhdGUgJWluJSBSMiB+ICcyJywKICAgICAgICAgICAgc3RhdGUgJWluJSBSMyB+ICczJywKICAgICAgICAgICAgc3RhdGUgJWluJSBSNCB+ICc0JywKICAgICAgICAgICAgc3RhdGUgJWluJSBSNSB+ICc1JywKICAgICAgICAgICAgc3RhdGUgJWluJSBSNiB+ICc2JywKICAgICAgICAgICAgc3RhdGUgJWluJSBSNyB+ICc3JywKICAgICAgICAgICAgc3RhdGUgJWluJSBSOCB+ICc4JywKICAgICAgICAgICAgc3RhdGUgJWluJSBSOSB+ICc5JywKICAgICAgICAgICAgc3RhdGUgJWluJSBSMTAgfiAnMTAnLCAKICAgICAgICAgICAgVFJVRSB+ICdPdGhlcicpCikpCmBgYAoKCmBgYHtyIFBDQSBBdHRlbXB0LCBldmFsID0gRn0KI1JlZmVyZW5jZSBEb2N1bWVudGF0aW9uIDogaHR0cHM6Ly9wbG90bHkuY29tL3IvcmVmZXJlbmNlLyNwYXJjb29yZHMKCiNETyBOT1QgUlVOIFlFVC4gaGF2ZSBub3QgdXBkYXRlZCBjb21wbGV0ZWx5CmZpZyA8LSBkYXQgJT4lCiAgcGxvdF9seSh3aWR0aCA9IDEwMDAsIGhlaWdodCA9IDYwMCkgCmZpZyA8LSBmaWcgJT4lIGFkZF90cmFjZSh0eXBlID0gJ3BhcmNvb3JkcycsIG5hbWUgPSB+c3RhdGUsCiAgICAgICAgICBkaW1lbnNpb25zID0gbGlzdCgKICAgICAgICAgICAgbGlzdCh0aWNrdmFscyA9IGMoMDo1MCksCiAgICAgICAgICAgICAgICAgdGlja3RleHQgPSBjKGRhdCRzdGF0ZSksCiAgICAgICAgICAgICAgICAgbGFiZWwgPSAnU3RhdGUnLCB2YWx1ZXMgPSB+c3RhdGUpLAogICAgICAgICAgICBsaXN0KAogICAgICAgICAgICAgIHJhbmdlPWMofm1pbih0b3RhbFRlc3RSZXN1bHRzKSwgfm1heCh0b3RhbFRlc3RSZXN1bHRzKSksCiAgICAgICAgICAgICAgbGFiZWwgPSAnVG90YWwgVGVzdHMnLAogICAgICAgICAgICAgIHZhbHVlcyA9IH50b3RhbFRlc3RSZXN1bHRzKQogICAgICAgICAgICAKICAgICAgICAgICAgIyBsaXN0KHJhbmdlID0gYyh+bWluKGJsb2NrSGVpZ2h0KSx+bWF4KGJsb2NrSGVpZ2h0KSksCiAgICAgICAgICAgICMgICAgICBjb25zdHJhaW50cmFuZ2UgPSBjKDEwMDAwMCwxNTAwMDApLAogICAgICAgICAgICAjICAgICAgbGFiZWwgPSAnQmxvY2sgSGVpZ2h0JywgdmFsdWVzID0gfmJsb2NrSGVpZ2h0KSwKICAgICAgICAgICAgIyBsaXN0KHJhbmdlID0gYyh+bWluKGJsb2NrV2lkdGgpLH5tYXgoYmxvY2tXaWR0aCkpLAogICAgICAgICAgICAjICAgICAgbGFiZWwgPSAnQmxvY2sgV2lkdGgnLCB2YWx1ZXMgPSB+YmxvY2tXaWR0aCksCiAgICAgICAgICAgICMgbGlzdCh0aWNrdmFscyA9IGMoMCwwLjUsMSwyLDMpLAogICAgICAgICAgICAjICAgICAgdGlja3RleHQgPSBjKCdBJywnQUInLCdCJywnWScsJ1onKSwKICAgICAgICAgICAgIyAgICAgIGxhYmVsID0gJ0N5Y2xpbmRlciBNYXRlcmlhbCcsIHZhbHVlcyA9IH5jeWNNYXRlcmlhbCksCiAgICAgICAgICAgICMgbGlzdChyYW5nZSA9IGMoLTEsNCksCiAgICAgICAgICAgICMgICAgICB0aWNrdmFscyA9IGMoMCwxLDIsMyksCiAgICAgICAgICAgICMgICAgICBsYWJlbCA9ICdCbG9jayBNYXRlcmlhbCcsIHZhbHVlcyA9IH5ibG9ja01hdGVyaWFsKSwKICAgICAgICAgICAgIyBsaXN0KHJhbmdlID0gYyh+bWluKHRvdGFsV2VpZ2h0KSx+bWF4KHRvdGFsV2VpZ2h0KSksCiAgICAgICAgICAgICMgICAgICB2aXNpYmxlID0gVFJVRSwKICAgICAgICAgICAgIyAgICAgIGxhYmVsID0gJ1RvdGFsIFdlaWdodCcsIHZhbHVlcyA9IH50b3RhbFdlaWdodCksCiAgICAgICAgICAgICMgbGlzdChyYW5nZSA9IGMofm1pbihhc3NlbWJseVBXKSx+bWF4KGFzc2VtYmx5UFcpKSwKICAgICAgICAgICAgIyAgICAgIGxhYmVsID0gJ0Fzc2VtYmx5IFBlbmFsdHkgV2VpZ2h0JywgdmFsdWVzID0gfmFzc2VtYmx5UFcpLAogICAgICAgICAgICAjIGxpc3QocmFuZ2UgPSBjKH5taW4oSHN0Vyksfm1heChIc3RXKSksCiAgICAgICAgICAgICMgICAgICBsYWJlbCA9ICdIZWlnaHQgc3QgV2lkdGgnLCB2YWx1ZXMgPSB+SHN0VyksCiAgICAgICAgICAgICMgbGlzdChyYW5nZSA9IGMofm1pbihtaW5IVyksfm1heChtaW5IVykpLAogICAgICAgICAgICAjICAgICAgbGFiZWwgPSAnTWluIEhlaWdodCBXaWR0aCcsIHZhbHVlcyA9IH5taW5IVyksCiAgICAgICAgICAgICMgbGlzdChyYW5nZSA9IGMofm1pbihtaW5XRCksfm1heChtaW5XRCkpLAogICAgICAgICAgICAjICAgICAgbGFiZWwgPSAnTWluIFdpZHRoIERpYW1ldGVyJywgdmFsdWVzID0gfm1pbldEKSwKICAgICAgICAgICAgIyBsaXN0KHJhbmdlID0gYyh+bWluKHJmQmxvY2spLH5tYXgocmZCbG9jaykpLAogICAgICAgICAgICAjICAgICAgbGFiZWwgPSAnUkYgQmxvY2snLCB2YWx1ZXMgPSB+cmZCbG9jaykKICAgICAgICAgICAgKQogICAgICAgICAgKQoKCmZpZwpgYGAKCkdHYWxseQptb3JlIGRpZmZpY3VsdCB0byBkbyBjYXRlZ29yaWNhbCBkYXRhLCBidXQgd2F5IHRvIHNlcGFyYXRlIG91dCBncm91cHMsIHNjYWxlIHRoZSBkYXRhICh1bml2YXJpYXRlbHksIHN1YnN0cmFjdCBtZWFuICYgZGl2aWRlIGJ5IHNkKQpgYGB7cn0KbGlicmFyeShHR2FsbHkpCmRhdCAlPiUgYXJyYW5nZShkZXNjKHJlZ2lvbikpJT4lCiAgIGdncGFyY29vcmQoCiAgICBjb2x1bW5zID0gYygxOCwyOSksIGdyb3VwQ29sdW1uID0gMzIKICAgICkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCAiIzY5YjNhMiIsICIjRThFOEU4IiwgIiNFOEU4RTgiLCAiI0U4RThFOCIsICIjRThFOEU4IiwgIiNFOEU4RTgiLCAiI0U4RThFOCIsICIjRThFOEU4IiwgIiNFOEU4RTgiLCAiI0U4RThFOCIsICIjRThFOEU4IikgKSAKCiAjY2FuIGZhY3RvciByZWdpb25zCiNkYXQgJT4lIGNvbG5hbWVzKCkKYGBgCgpUSElTIE9ORSEhIGNkcGFyY29vcmQKYGBge3J9CmxpYnJhcnkoY2RwYXJjb29yZCkKCmRhdGEoZGF0KQpwY2RhdDwtIGRhdFsxOjU0LGMoMiwxOCwyOSwzMildICU+JSBzdWJzZXQoIWlzLm5hKGRhdFsxOjU0LDI5XSkpCmRpc2NwYXJjb29yZChwY2RhdCxrPTE1MCxzYXZlQ291bnRzPUZBTFNFKSAgCmBgYAoKCg==